/*
 * keyboard.c
 *
 *  Created on: 2016-10-25
 *      Author: m
 */
#include "keyboard.h"
#include "string.h"
#include "sub.h"
#include "kernel.h"
#include "i8259.h"
#include "tty.h"
#include "global.h"
#include "q.h"
/*
    +--PC--------------------------------+
    |                                    |
    | i386<----+                         |
    |          |                         |
    |       8259A<---+                   |
    |                |                   |
    |         8042(Key Controller)       |
    |                    |               |
    +--------------------+---------------+
                         |
    +--KeyBoard----------+---------------+
    |                    |               |
    |           8048(Keyboard Encoder)   |
    |                                    |
    +------------------------------------+
# 动作可以分解成三类:按下、保持按住的状态以及放开;内容则是键盘上不同的键,字母键还是数字键,回车键还是箭头键。
  根据敲击动作产生的编码,8048既要反映“哪个”按键产生了动作,还要反映产生了“什么”动作。
# 敲击键盘所产生的编码被称作扫描码(Scan Code),它分为Make Code和Break Code两类。当一个键被按下或者保持住按下时,将会产生Make Code,
  当键弹起时,产生Break Code。除了Pause键之外,每一个按键都对应一个Make Code和一个Break Code
# 扫描码总共有三套,叫做Scan code set 1、Scan code set 2和Scan code set 3。Scan code set 1是早期的XT键盘使用的,
  现在的键盘默认都支持Scan code set 2,而Scan code set 3很少使用
# 当8048检测到一个键的动作后,会把相应的扫描码发送给8042,8042会把它转换成相应的Scan code set 1扫描码,并将其放置在输入缓冲区中,
  然后8042告诉8259A产生中断(IRQ1)。如果此时键盘又有新的键被按下,8042将不再接收,一直到缓冲区被清空,8042才会收到更多的扫描码

  8042寄存器(RW相关以i386视角)
  寄存器名称     寄存器大小       端口      R/W     用法
  输出缓冲区     1BYTE          0x60     Read    读输出缓冲区
  输入缓冲区     1BYTE          0x60     Write   写输入缓冲区
  状态寄存器     1BYTE          0x64     Read    读状态寄存器
  控制寄存器     1BYTE          0x64     Write   发送命令

KEY       MAKE              BREAK
A         1E                9E
B         30                B0
C         2E                AE
D         20                A0
E         12                92
F         21                A1
G         22                A2
H         23                A3
I         17                97
J         24                A4
K         25                A5
L         26                A6
M         32                B2
N         31                B1
O         18                98
P         19                99
Q         10                90
R         13                93
S         1F                9F
T         14                94
U         16                96
V         2F                AF
W         11                91
X         2D                AD
Y         15                95
Z         2C                AC
0         0B                8B
1         2                 82
2         3                 83
3         4                 84
4         5                 85
5         6                 86
6         7                 87
7         8                 88
8         9                 89
9         0A                8A
`         29                89
-         0C                8C
=         0D                8D
\         2B                AB
BKSP      0E                8E
SPACE     39                B9
TAB       0F                8F
CAPS      3A                BA
L SHFT    2A                AA
L CTRL    1D                9D
L GUI(WIN)E0,5B             E0,DB
L ALT     38                B8
R SHFT    36                B6
R CTRL    E0,1D             E0,9D
R GUI(WIN)E0,5C             E0,DC
R ALT     E0,38             E0,B8
APPS      E0,5D             E0,DD
ENTER     1C                9C
ESC       1                 81
F1        3B                BB
F2        3C                BC
F3        3D                BD
F4        3E                BE
F5        3F                BF
F6        40                C0
F7        41                C1
F8        42                C2
F9        43                C3
F10       44                C4
F11       57                D7
F12       58                D8
PRNT/SCRN E0,2A,E0,37       E0,B7,E0,AA
SCROLL    46                C6
PAUSE     E1,1D,45,E1,9D,C5 -NONE-
[         1A                9A
INSERT    E0,52             E0,D2
HOME      E0,47             E0,97
PG UP     E0,49             E0,C9
DELETE    E0,53             E0,D3
END       E0,4F             E0,CF
PG DN     E0,51             E0,D1
U ARROW   E0,48             E0,C8
L ARROW   E0,4B             E0,CB
D ARROW   E0,50             E0,D0
R ARROW   E0,4D             E0,CD
NUM       45                C5
KP /      E0,35             E0,B5
KP *      37                B7
KP -      4A                CA
KP +      4E                CE
KP EN     E0,1C             E0,9C
KP .      53                D3
KP 0      52                D2
KP 1      4F                CF
KP 2      50                D0
KP 3      51                D1
KP 4      4B                CB
KP 5      4C                CC
KP 6      4D                CD
KP 7      47                C7
KP 8      48                C8
KP 9      49                C9
]         1B                9B
;         27                A7
'         28                A8
,         33                B3
.         34                B4
/         35                B5

http://www.quadibloc.com/comp/scan.htm
*/

u8 keyset1code_to_vkey[128] = {
    0, //0x0(0)
    KEY_ESC, //0x1(1)
    KEY_1, //0x2(2)
    KEY_2, //0x3(3)
    KEY_3, //0x4(4)
    KEY_4, //0x5(5)
    KEY_5, //0x6(6)
    KEY_6, //0x7(7)
    KEY_7, //0x8(8)
    KEY_8, //0x9(9)
    KEY_9, //0xA(10)
    KEY_0, //0xB(11)
    KEY_MINUS, //0xC(12)
    KEY_EQUAL, //0xD(13)
    KEY_BACKSPACE, //0xE(14)
    KEY_TAB, //0xF(15)
    KEY_Q, //0x10(16)
    KEY_W, //0x11(17)
    KEY_E, //0x12(18)
    KEY_R, //0x13(19)
    KEY_T, //0x14(20)
    KEY_Y, //0x15(21)
    KEY_U, //0x16(22)
    KEY_I, //0x17(23)
    KEY_O, //0x18(24)
    KEY_P, //0x19(25)
    KEY_LEFTBRACE, //0x1A(26)
    KEY_RIGHTBRACE, //0x1B(27)
    KEY_ENTER, //0x1C(28)
    KEY_LEFTCTRL, //0x1D(29)
    KEY_A, //0x1E(30)
    KEY_S, //0x1F(31)
    KEY_D, //0x20(32)
    KEY_F, //0x21(33)
    KEY_G, //0x22(34)
    KEY_H, //0x23(35)
    KEY_J, //0x24(36)
    KEY_K, //0x25(37)
    KEY_L, //0x26(38)
    KEY_SEMICOLON, //0x27(39)
    KEY_APOSTROPHE, //0x28(40)
    KEY_GRAVE, //0x29(41)
    KEY_LEFTSHIFT, //0x2A(42)
    KEY_BACKSLASH, //0x2B(43)
    KEY_Z, //0x2C(44)
    KEY_X, //0x2D(45)
    KEY_C, //0x2E(46)
    KEY_V, //0x2F(47)
    KEY_B, //0x30(48)
    KEY_N, //0x31(49)
    KEY_M, //0x32(50)
    KEY_COMMA, //0x33(51)
    KEY_DOT, //0x34(52)
    KEY_SLASH, //0x35(53)
    KEY_RIGHTSHIFT, //0x36(54)
     KEY_KPASTERISK, //0x37(55)
    KEY_LEFTALT, //0x38(56)
    KEY_SPACE, //0x39(57)
    KEY_CAPSLOCK, //0x3A(58)
    KEY_F1, //0x3B(59)
    KEY_F2, //0x3C(60)
    KEY_F3, //0x3D(61)
    KEY_F4, //0x3E(62)
    KEY_F5, //0x3F(63)
    KEY_F6, //0x40(64)
    KEY_F7, //0x41(65)
    KEY_F8, //0x42(66)
    KEY_F9, //0x43(67)
    KEY_F10, //0x44(68)
    KEY_NUMLOCK, //0x45(69)
    KEY_SCROLLLOCK, //0x46(70)
    KEY_KP7, //0x47(71)
    KEY_KP8, //0x48(72)
    KEY_KP9, //0x49(73)
    KEY_KPMINUS, //0x4A(74)
    KEY_KP4, //0x4B(75)
    KEY_KP5, //0x4C(76)
    KEY_KP6, //0x4D(77)
    KEY_KPPLUS, //0x4E(78)
    KEY_KP1, //0x4F(79)
    KEY_KP2, //0x50(80)
    KEY_KP3, //0x51(81)
    KEY_KP0, //0x52(82)
    KEY_KPDOT, //0x53(83)
    0, //0x54(84)
    0, //0x55(85)
    0, //0x56(86)
    KEY_F11, //0x57(87)
    KEY_F12, //0x58(88)
    0, //0x59(89)
    0, //0x5A(90)
    0, //0x5B(91)
    0, //0x5C(92)
    0, //0x5D(93)
    0, //0x5E(94)
    0, //0x5F(95)
    0, //0x60(96)
    0, //0x61(97)
    0, //0x62(98)
    0, //0x63(99)
    0, //0x64(100)
    0, //0x65(101)
    0, //0x66(102)
    0, //0x67(103)
    0, //0x68(104)
    0, //0x69(105)
    0, //0x6A(106)
    0, //0x6B(107)
    0, //0x6C(108)
    0, //0x6D(109)
    0, //0x6E(110)
    0, //0x6F(111)
    0, //0x70(112)
    0, //0x71(113)
    0, //0x72(114)
    0, //0x73(115)
    0, //0x74(116)
    0, //0x75(117)
    0, //0x76(118)
    0, //0x77(119)
    0, //0x78(120)
    0, //0x79(121)
    0, //0x7A(122)
    0, //0x7B(123)
    0, //0x7C(124)
    0, //0x7D(125)
    0, //0x7E(126)
    0, //0x7F(127)
};
#define KB_Q_BUF_SIZE   (512)
static char kbq_buf[KB_Q_BUF_SIZE] = {0};
static Q kbq;

void init_keyboard() {
    set_irq_handler(KEYBOARD_IRQ, keyboard_handler);
    enable_irq(KEYBOARD_IRQ);
    q_init(&kbq, kbq_buf, KB_Q_BUF_SIZE, 1);
}

static void add_key_event(Q* tty_q, u8 xkey) {//u8 type, u8 vkey) {
    q_push(tty_q, &xkey);
}

struct {
    u8 sub_code;
    u8 vkey;
} sub0xE0_to_vkey_map [] = {
    {0x5B, KEY_LEFT_WIN},
    {0x1D, KEY_RIGHTCTRL},
    {0x5C, KEY_RIGHT_WIN},
    {0x38, KEY_RIGHTALT},
    {0x5D, KEY_MENU},
    {0x52, KEY_INSERT},
    {0x47, KEY_HOME},
    {0x49, KEY_PAGEUP},
    {0x53, KEY_DELETE},
    {0x4F, KEY_END},
    {0x51, KEY_PAGEDOWN},
    {0x48, KEY_UP},
    {0x4B, KEY_LEFT},
    {0x50, KEY_DOWN},
    {0x4D, KEY_RIGHT},
    {0x35, KEY_KPSLASH},
    {0x1C, KEY_KPENTER},
};

void keyboard_read(Q* tty_q) {
    u8 ev, make, c, k, len, c1, c2, c3, c4, c5;

    if(0 == kbq.count) return;
    q_front(&kbq, &c, 0);
    if(0xE0 == c) {
        len = 2;
        if(kbq.count > 1) {
            q_front(&kbq, &c1, 1);
            if(0x2A == c1 || 0xB7 == c1) {
                len = 4;
            }
        }
    } else if(0xE1 == c) {
        len = 6;
    } else {
        len = 1;
    }
    if(kbq.count < len) {
        return;
    }

    if(1 == len) {
        ev = (c & 0x80) ? EV_REL : EV_KEY;
        make = c & 0x7F;
        k = keyset1code_to_vkey[make];
        add_key_event(tty_q, ev | k);
    } else if(2 == len) {
        if(0x47 == c1) {
            add_key_event(tty_q, EV_KEY | KEY_HOME);
        } else if(0x97 == c1) {
            add_key_event(tty_q, EV_REL | KEY_HOME);
        } else {
            ev = (c1 & 0x80) ? EV_REL : EV_KEY;
            make = c1 & 0x7F;
            for(int i = 0; i < sizeof(sub0xE0_to_vkey_map) / sizeof(sub0xE0_to_vkey_map[0]); ++i) {
                if(sub0xE0_to_vkey_map[i].sub_code == make) {
                    k = sub0xE0_to_vkey_map[i].vkey;
                    add_key_event(tty_q, ev | k);
                    break;
                }
            }
        }
    } else if(4 == len) {
        q_front(&kbq, &c2, 2);
        q_front(&kbq, &c3, 3);
        if(0x2A == c1 && 0xE0 == c2 && 0x37 == c3) {
            add_key_event(tty_q, EV_KEY | KEY_PRINT_SCREEN);
        } else if(0xB7 == c1 && 0xE0 == c2 && 0xAA == c3) {
            add_key_event(tty_q, EV_REL | KEY_PRINT_SCREEN);
        }
    } else if(6 == len) {
        q_front(&kbq, &c1, 1);
        q_front(&kbq, &c2, 2);
        q_front(&kbq, &c3, 3);
        q_front(&kbq, &c4, 4);
        q_front(&kbq, &c5, 5);
        if(0x1D == c1 && 0x45 == c2 && 0xE1 == c3 && 0x9D == c4 && 0xC5 == c5) {
            add_key_event(tty_q, EV_KEY | KEY_PAUSE);
        }
    }
    for(int i = 0; i < len; ++i) {
        q_pop(&kbq, &c);
    }
}

void keyboard_handler(int irq_no) {
    char c = in_byte(0x60);
    q_push(&kbq, &c);
}
